//
// Created by LiuYou on 2021/10/29.
//

#include <iostream>
#include <cstring>


static const int THREAD_NUM = 20;

static const char* const FILE_NAME = "/tmp/out";

static const int LINE_BUF = 1024;


int main(int argc, char** argv) {
//    FILE_NAME
    pthread_t tidArray[THREAD_NUM]{};
    for (int i = 0; i < THREAD_NUM; ++i) {
        int errorNumber = pthread_create(
                tidArray + i, nullptr,
                [](void* args) -> void* {

                    /*
                     *todo 笔记:
                     * 这个程序之所以出问题, 分析一下,
                     * 如果是20个线程同时打开同一个文件可不可以?
                     * 可以。
                     */
                    FILE* fp = fopen( FILE_NAME, "r+" );
                    if (fp == nullptr) {
                        perror( "fopen()" );
                        pthread_exit( nullptr );
                    }
                    pthread_cleanup_push( [](void* args) {
                        fclose((FILE*) args );
                    }, fp );
                    pthread_cleanup_pop( 1 );

                    char lineBuf[LINE_BUF]{};
                    /*
                     *todo 笔记:
                     * 如果是20个线程同时读有没有问题?
                     * 其实也可以, 但是有前提条件:
                     * 这20个线程对这个文件只是只读,
                     * 那可以20个线程同时读, 因为谁也不会改！
                     * 但是, 在这儿不行, 因为这份代码
                     * 同时运行着20份。
                     * 所以, 要想到, 假如某个线程在执行
                     * 这句代码的时候, 别的线程在执行写,
                     * 那就完蛋了。
                     * 所以, 这里20个线程同时读是不行的！
                     * 必须要一个一个读, 因为读完了接着就是写。
                     */
                    fgets( lineBuf, LINE_BUF, fp );

                    // 把文件指针定位到文件开始处。
                    fseek( fp, 0, SEEK_SET );
                    /*
                     *todo 笔记:
                     * 那么20个人同时写, 当然是一定不行的。
                     *
                     *todo 笔记:
                     * 另外, fprintf();是往一个文件内写,
                     * 文件的全缓冲模式, 所以, 一定要
                     * 使用 fflush();将内容真正写到 fd 中去,
                     * 而不是将写到内容在缓冲区停留(等缓冲区满了再刷新)！
                     *
                     *todo 笔记:
                     * 所以这样就分析出来了, 我们把同一时刻只能一个线程来
                     * 执行的一句代码或者一段代码, 把这段代码称为临界区。
                     * 为了解决竞争冲突, 我们需要在临界区前把这段代码 加锁,
                     * 离开临界区的时候把这段代码 解锁。
                     */
                    fprintf( fp, "%d\n", (atoi( lineBuf ) + 1));


                    pthread_exit( nullptr );
                },
                nullptr );
        if (errorNumber != 0) {
            fprintf( stderr, "pthread_create(): %s.\n", strerror( errorNumber ));
            return 1;
        }
    }


    for (int i = 0; i < THREAD_NUM; ++i) {
        pthread_join( tidArray[i], nullptr );
    }


    return 0;
}
